package com.hontech.bvapp2.service

import com.hontech.bvapp2.utils.log
import com.hontech.bvapp2.utils.macAddr
import com.hontech.bvapp2.utils.runNet
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.encodeToByteArray


private const val EC_NO_DEVICE = 1
private const val EC_NO_LOGIN = 2
private const val EC_TOKEN_INVALID = 3
private const val EC_RX_WAIT_TIMEOUT = 4
private const val EC_RECV_TIMEOUT = 5

private const val TY_NOTIFY = 0
private const val TY_REQ = 1
private const val TY_RES = 2


private suspend fun run() {

    var res = login()

    while (true) {
        try {
            val msg = poll(res)
            when (msg.ty) {
                TY_REQ -> {
                    val data = onReq(msg)
                    Http.post(
                        "/msg/device/res", data, arrayOf(
                            Pair("id", res.id.toString()),
                            Pair("seq", msg.seq.toString())
                        )
                    )
                }

                TY_NOTIFY -> onNotify(msg)
            }
        } catch (e: ServiceException) {
            when (e.ec) {
                EC_NO_LOGIN, EC_TOKEN_INVALID -> {
                    res = login()
                }

                EC_RX_WAIT_TIMEOUT, EC_RECV_TIMEOUT -> {
                    log(e.msg)
                }
            }
        }
    }
}

private suspend fun onNotify(msg: MsgItem) {

}

private suspend fun poll(res: LoginRes) = runNet {
    val resp = Http.get(
        "/msg/device/poll", arrayOf(
            Pair("id", res.id.toString()),
            Pair("token", res.token)
        )
    )
    val seq = resp.header("seq")?.toInt() ?: throw IllegalStateException("no seq")
    val ty = resp.header("ty")?.toInt() ?: throw IllegalStateException("no ty")
    val cmd = resp.header("cmd") ?: throw IllegalStateException("no cmd")
    val body = resp.body?.bytes() ?: throw IllegalStateException("no body")
    MsgItem(seq, ty, body, cmd)
}

class MsgItem(
    val seq: Int,
    val ty: Int,
    val body: ByteArray,
    val cmd: String
) {

    fun res(resBody: ByteArray): MsgItem {
        return MsgItem(seq, TY_RES, resBody, cmd)
    }
}

@Serializable
private class LoginReq(
    @SerialName("mac_addr")
    val macAddr: String
)

@Serializable
private class LoginRes(
    val token: String,
    val id: Long
)

@OptIn(ExperimentalSerializationApi::class)
private suspend fun login() = runNet {
    val body = Cbor.encodeToByteArray(LoginReq(macAddr))
    val resp = Http.post("/msg/device/login", body)
    val res: LoginRes = resp.parse()
    res
}

























